using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Streambolics.Gui
{
    public partial class StandardUserControl
    {
        private MouseEventArgs _LastMouseDown;
        private bool _AllowDragStart = true;

        protected static Cursor _DragCursor;
        protected static Cursor _TransparentCursor;

        /// <summary>
        ///     Builds the appropriate drag-and-drop cursor
        /// </summary>
        /// <param name="e">
        ///     The mouse event that started the drag operation.
        /// </param>
        /// <param name="aDisabled">
        ///     Whether the cursor should be for a disabled drop.
        /// </param>
        /// <returns>
        ///     The cursor to use.
        /// </returns>

        protected Cursor BuildCursor (MouseEventArgs e, bool aDisabled)
        {
            return DragAdapter.BuildCursor (this, e, aDisabled);
        }

        private void drag_MouseMove (MouseEventArgs e)
        {
            if (_LastMouseDown != null)
            {
                // Yes, this is a Manhattan distance. Good enough...
                int n = Math.Abs (e.X - _LastMouseDown.X) + Math.Abs (e.Y - _LastMouseDown.Y);
                if (n > 5)
                {
                    DoDragStart ();
                }
            }
        }

        private void drag_MouseDown (MouseEventArgs e)
        {
            if (_AllowDragStart || e.Button != MouseButtons.Left)
            {
                _LastMouseDown = e;
            }
        }

        private void drag_MouseUp (MouseEventArgs e)
        {
            _LastMouseDown = null;
        }

        private void drag_MouseLeave (EventArgs e)
        {
            DoDragStart ();
        }

        /// <summary>
        ///     Evnet fired when a drag operation can be started.
        /// </summary>
        /// <param name="e">
        ///     The event corresponding to the drag start.
        /// </param>
        /// <remarks><para>
        ///     When this event is called, the EventArgs are empty. If 
        ///     the callback function wants to really start a drag operation,
        ///     it should fill the properties of the EventArgs, at least with
        ///     the data to be dragged.
        /// </para></remarks>

        protected virtual void OnDragStart (DragStartEventArgs e)
        {
        }

        private void DoDragStart ()
        {
            if (_LastMouseDown != null)
            {
                MouseEventArgs e = _LastMouseDown;
                _LastMouseDown = null;
                DragStartEventArgs ee = new DragStartEventArgs (e);
                OnDragStart (ee);

                if (ee.DragObject != null)
                {
                    _DragCursor = ee.DragCursor == null ? BuildCursor (e, false) : ee.DragCursor;
                    _TransparentCursor = ee.TransparentCursor == null ? BuildCursor (e, true) : ee.TransparentCursor;
                    DoDragDrop (ee.DragObject, ee.Effects);
                }
            }
        }

        /// <summary>
        ///     Whether dragging is allowed for the control.
        /// </summary>

        public bool AllowDragStart
        {
            get
            {
                return _AllowDragStart;
            }
            set
            {
                _AllowDragStart = value;
            }
        }

        /// <summary>
        ///     Overridden to provide an appropriate drag cursor.
        /// </summary>
        /// <param name="e">
        ///     The EventArgs corresponding to the drag operation.
        /// </param>

        protected override void OnGiveFeedback (GiveFeedbackEventArgs e)
        {
            base.OnGiveFeedback (e);

            if (_DragCursor != null && e.Effect != DragDropEffects.None)
            {
                e.UseDefaultCursors = false;
                Cursor.Current = _DragCursor;
            }
            else if (_TransparentCursor != null)
            {
                e.UseDefaultCursors = false;
                Cursor.Current = _TransparentCursor;
            }
        }
    }
}
